package logic

import (
	"context"
	"strings"

	"mall/common/enumx"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/service/blog/model"
	"mall/service/blog/rpc/internal/svc"
	"mall/service/blog/rpc/types/blog"

	"github.com/zeromicro/go-zero/core/logx"
)

type PageDetailLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewPageDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PageDetailLogic {
	return &PageDetailLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *PageDetailLogic) PageDetail(in *blog.PageDetailRequest) (*blog.PageDetailResponse, error) {
	if in.Preload == "" && in.EagerLoad == "" {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	logx.Infof("PageDetailRequest: %+v ", in)
	// Preload:\"blogPage:Title,Id,Uri;blogPageDetail:ContentHtml;blogMedia:altText,sourceUrl,mediaDetails;blogPageMeta:fullHead,title,metaDesc\" EagerLoad:\"blogPage:blogPageDetail,blogMedia,blogPageMeta\" Filter:\"Uri,equalTo:homepage\"

	preloadMap, eagerLoadMap := modelx.GetPreloadMap(in.Preload, in.EagerLoad)
	// logx.Infof("preloadMap: %+v ", preloadMap)
	// preloadMap: map[blogMedia:[altText sourceUrl mediaDetails] blogPage:[Title Id Uri] blogPageDetail:[ContentHtml] blogPageMeta:[fullHead title metaDesc]]
	// logx.Infof("eagerLoadMap: %+v ", eagerLoadMap)
	// eagerLoadMap: map[blogPage:[blogPageDetail blogMedia blogPageMeta]]

	blogPageEntityName := model.RpcEntityNames.BlogPage
	_, hasEntitySettings := model.RpcEntityPreloadMap[blogPageEntityName] // BlogPage的关联字段
	if !hasEntitySettings {
		return &blog.PageDetailResponse{}, nil
	}

	blogPageRepositoryName := model.RepositoryNames.BlogPage
	columnMap, hasColumnMap := model.RepositoryPreloadMap[blogPageRepositoryName] // BlogPage的数据库字段
	if !hasColumnMap {
		return &blog.PageDetailResponse{}, nil
	}

	var selectCols []string
	if preloadFields, hasPreloadFields := preloadMap[blogPageEntityName]; hasPreloadFields {
		selectColMap := make(map[string]string) // 去重的select columns
		for _, field := range preloadFields { // 解析Preload
			if _, exist := selectColMap[field]; !exist {
				if column, hasColumn := columnMap[field]; hasColumn {
					selectColMap[field] = column
				} else {
					selectColMap[field] = ""
				}
			}
		}
		for _, column := range selectColMap {
			if column != "" {
				selectCols = append(selectCols, column)
			}
		}
	}

	var page *model.BlogPage
	if in.Filter != "" {
		var filterMap map[string]map[string][]interface{}
		filterMap = modelx.GetFilterMap(in.Filter, columnMap)
		// logx.Infof("filterMap: %+v ", filterMap)
		// filterMap: map[post_name:map[equalTo:[homepage]]]

		var asPreview string
		if in.AsPreview {
			asPreview = "1"
		}
		var pageSize int64 = 1
		pageList, _, err := l.svcCtx.BlogPage.GetList(l.ctx, model.M{
			"asPreview": asPreview,
			"pageSize":  pageSize,
			"select":    strings.Join(selectCols, ","),
		}, -1, filterMap)
		if err != nil {
			return nil, err
		}
		if len(pageList) == 0 {
			return &blog.PageDetailResponse{}, nil
		}

		page = pageList[0]
	} else if in.Id > 0 {
		pageSingle, err := l.svcCtx.BlogPage.FindOne(l.ctx, in.Id, selectCols)
		if err != nil {
			if err == model.ErrNotFound {
				return &blog.PageDetailResponse{}, nil
			}

			return nil, err
		}

		page = pageSingle
	}

	if page == nil {
		return &blog.PageDetailResponse{}, nil
	}

	var contentHtml string
	var media []*blog.BlogMedia
	var meta []*blog.BlogMeta
	subRpcEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
	if eagerLoadRpcEntities, hasEagerLoadRpcEntities := eagerLoadMap[blogPageEntityName]; hasEagerLoadRpcEntities {
		for _, entity := range eagerLoadRpcEntities {
			if rpcEntitySettingMap, hasRpcEntitySettingMap := model.RpcEntityPreloadMap[entity]; hasRpcEntitySettingMap {
				subRpcEntitySettingMap[entity] = rpcEntitySettingMap
			}
		}
	}

	blogPageDetailRpcEntityName := model.RpcEntityNames.BlogPageDetail
	blogPageDetailRepositoryName := model.RepositoryNames.BlogPageDetail
	if _, hasRpcEntitySettingMap := subRpcEntitySettingMap[blogPageDetailRpcEntityName]; hasRpcEntitySettingMap {
		preloadFields, hasPreloadFields := preloadMap[blogPageDetailRpcEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogPageDetailRepositoryName]
		if hasPreloadFields && hasSubColumnMap {
			selectColMap := make(map[string]string)
			for _, field := range preloadFields {
				if _, exist := selectColMap[field]; !exist {
					if column, hasColumn := subColumnMap[field]; hasColumn {
						selectColMap[field] = column
					} else {
						selectColMap[field] = ""
					}
				}
			}
			var subSelectCols []string
			for _, column := range selectColMap {
				if column != "" {
					subSelectCols = append(subSelectCols, column)
				}
			}

			detailFilterMap := make(map[string]map[string][]interface{})
			detailFilterMap[model.BlogPageDetailColumns.PageID] = map[string][]interface{}{
				"equalTo": []interface{}{page.ID},
			}
			var pageSize int64 = 1
			detailList, _, err := l.svcCtx.BlogPage.GetDetail(l.ctx, model.M{
				"pageSize": pageSize,
				"select":   strings.Join(subSelectCols, ","),
			}, -1, detailFilterMap)
			if err != nil {
				return nil, err
			}
			if len(detailList) > 0 {
				contentHtml = detailList[0].PostContent
			}
		}
	}

	blogMediaRpcEntityName := model.RpcEntityNames.BlogMedia
	blogMediaRepositoryName := model.RepositoryNames.BlogMedia
	if _, hasRpcEntitySettingMap := subRpcEntitySettingMap[blogMediaRpcEntityName]; hasRpcEntitySettingMap {
		preloadFields, hasPreloadFields := preloadMap[blogMediaRpcEntityName]
		subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[blogMediaRepositoryName]
		if hasPreloadFields && hasSubColumnMap {
			selectColMap := make(map[string]string)
			for _, field := range preloadFields {
				if _, exist := selectColMap[field]; !exist {
					if column, hasColumn := subColumnMap[field]; hasColumn {
						selectColMap[field] = column
					} else {
						selectColMap[field] = ""
					}
				}
			}
			var subSelectCols []string
			for _, column := range selectColMap {
				if column != "" {
					subSelectCols = append(subSelectCols, column)
				}
			}
			mediaFilterMap := make(map[string]map[string][]interface{})
			mediaFilterMap[model.BlogAttachmentRelationshipColumns.ObjectID] = map[string][]interface{}{
				"equalTo": []interface{}{page.ID},
			}
			mediaFilterMap[model.BlogAttachmentRelationshipColumns.ObjectType] = map[string][]interface{}{
				"equalTo": []interface{}{enumx.PostTypePage},
			}
			mediaFilterMap[model.BlogAttachmentRelationshipColumns.AttachmentThumbnail] = map[string][]interface{}{
				"equalTo": []interface{}{1},
			}
			mediaList, _, err := l.svcCtx.BlogPage.GetMedia(l.ctx, model.M{
				"orderBy": model.BlogAttachmentRelationshipColumns.AttachmentOrder,
				"select": strings.Join(subSelectCols, ","),
			}, -1, mediaFilterMap)
			if err != nil {
				return nil, err
			}
			if len(mediaList) > 0 {
				for _, mediaItem := range mediaList {
					media = append(media, &blog.BlogMedia{
						Uid: int64(mediaItem.AttachmentRelationshipID),
						Id: int64(mediaItem.AttachmentID),
						Uri: mediaItem.AttachmentSource,
						Thumbnail: int32(mediaItem.AttachmentThumbnail),
						Order: int32(mediaItem.AttachmentOrder),
						Url: mediaItem.AttachmentImageURL,
						AltText: mediaItem.AttachmentImageAlt,
						Meta: mediaItem.AttachmentImageMeta,
					})
				}
			}
		}
	}

	blogPageMetaRpcEntityName := model.RpcEntityNames.BlogPageMeta
	if rpcEntitySettingMap, hasRpcEntitySettingMap := subRpcEntitySettingMap[blogPageMetaRpcEntityName]; hasRpcEntitySettingMap {
		if preloadFields, hasPreloadFields := preloadMap[blogPageMetaRpcEntityName]; hasPreloadFields {
			var metaKeys []interface{}
			for _, field := range preloadFields {
				fieldSetting, hasFieldSetting := rpcEntitySettingMap[field]
				if hasFieldSetting && fieldSetting.Name != "" {
					metaKeys = append(metaKeys, fieldSetting.Name)
				}
			}
			if len(metaKeys) > 0 {
				metaFilterMap := make(map[string]map[string][]interface{})
				metaFilterMap[model.BlogPageMetumColumns.PageID] = map[string][]interface{}{
					"equalTo": []interface{}{page.ID},
				}
				metaFilterMap[model.BlogPageMetumColumns.MetaKey] = map[string][]interface{}{
					"in": metaKeys,
				}
				metaList, _, err := l.svcCtx.BlogPage.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
				if err != nil {
					return nil, err
				}
				if len(metaList) > 0 {
					for _, metum := range metaList {
						meta = append(meta, &blog.BlogMeta{
							Id: int64(metum.MetaID),
							Key: metum.MetaKey,
							Value: metum.MetaValue.String,
						})
					}
				}
			}
		}
	}

	return &blog.PageDetailResponse{
		Id:            int64(page.ID),
		AuthorId:      int64(page.PostAuthorID),
		ParentId:      int64(page.PostParentID),
		Title:         page.PostTitle,
		Excerpt:       page.PostExcerpt,
		Status:        int32(page.PostStatus),
		CommentStatus: int32(page.CommentStatus),
		Slug:          page.PostName,
		Uri:           page.GUID,
		Date:          modelx.FormatTime(page.PostDate, ""),
		DateGmt:       modelx.FormatTime(page.PostDateGMT, ""),
		Modified:      modelx.FormatTime(page.PostModifiedDate, ""),
		ModifiedGmt:   modelx.FormatTime(page.PostModifiedGMT, ""),
		CommentCount:  int32(page.CommentCount),
		ContentHtml:   contentHtml,
		SortOrder:     int64(page.MenuOrder),
		Media:         media,
		Meta:          meta,
	}, nil
}
